<template>
  <!-- 主容器：自定义标签页组件 -->
  <div class="custom-tabs" :class="{ 'custom-tabs--sticky': sticky && stickyFixed }">
    <!-- 滚动视图容器：用于横向滚动标签 -->
    <scroll-view 
      class="custom-tabs__wrap" 
      :class="{ 
        'custom-tabs__wrap--scrollable': scrollable, /* 可滚动样式 */
        'custom-tabs__wrap--sticky': sticky /* 吸顶样式 */
      }"
      :style="stickyFixed ? { top: offsetTop + 'px' } : null"
      ref="tabsWrap"
      :scroll-x="scrollable"
      :scroll-left="scrollLeft"
      :scroll-with-animation="true"
      :show-scrollbar="false"
      @scroll="onScroll"
    >
      <!-- 导航栏容器 -->
      <div class="custom-tabs__nav" id="scroll-nav-bar-nav" ref="tabsNav"
           :style="{
             backgroundColor: background, /* 背景颜色 */
             '--tabs-height': tabHeight + 'rpx', /* CSS变量：标签高度 */
             '--active-color': titleActiveColor, /* CSS变量：激活颜色 */
             '--inactive-color': titleInactiveColor /* CSS变量：未激活颜色 */
           }">
        <!-- 标签项循环 -->
        <div 
          v-for="(item, index) in items" 
          :key="index" 
          :id="`scroll-nav-bar-item-${index}`"
          class="custom-tabs__item" 
          :class="{ 
            'custom-tabs__item--active': index === active, /* 激活状态样式 */
            'custom-tabs__item--disabled': item.disabled /* 禁用状态样式 */
          }"
          :style="[
            index === active ? {color: titleActiveColor} : {color: titleInactiveColor}, /* 文字颜色 */
            {width: '140rpx', minWidth: '140rpx'} /* 固定宽度，确保标签大小一致 */
          ]"
          @click="onItemClick(item, index)"
          hover-class="none"
        >
          <!-- 标签图片（如果有） -->
          <div class="tab-img" v-if="item.imageUrl">
            <image :src="item.imageUrl" mode="aspectFill" />
          </div>
          <!-- 标签文本 -->
          <text class="custom-tabs__item-text">{{ item.name }}</text>
        </div>
        
        <!-- 底部指示线 -->
        <div class="custom-tabs__line" 
             :style="{
               width: lineWidth + 'px', /* 线条宽度 */
               transform: 'translateX(' + lineOffset + 'px)', /* 水平位移 */
               transitionDuration: localDuration + 's', /* 过渡动画时长 */
               height: lineHeight + 'px', /* 线条高度 */
               backgroundColor: titleActiveColor /* 线条颜色 */
             }"></div>
      </div>
    </scroll-view>
    
    <!-- 内容区域（可选） -->
    <div class="custom-tabs__content" v-if="showContent">
      <slot></slot> <!-- 插槽：用于放置标签页内容 -->
    </div>
  </div>
</template>

<script>
export default {
  name: 'scroll-nav-bar',
  props: {
    // 当前激活的标签索引，支持v-model双向绑定
    value: {
      type: Number,
      default: 0
    },
    // 标签项数组，每项可包含text(文本)、imageUrl(图片)、disabled(是否禁用)等属性
    items: {
      type: Array,
      default: () => []
    },
    // 动画过渡时间，单位秒
    duration: {
      type: [Number, String],
      default: 0.3
    },
    // 是否开启手势滑动切换标签页功能
    swipeable: {
      type: Boolean,
      default: false
    },
    // 是否允许标签栏在内容超出时横向滚动
    scrollable: {
      type: Boolean,
      default: true
    },
    // 是否启用吸顶效果
    sticky: {
      type: Boolean,
      default: false
    },
    // 吸顶时与顶部的距离，单位px
    offsetTop: {
      type: [Number, String],
      default: 0
    },
    // 标签栏背景颜色
    background: {
      type: String,
      default: '#fff'
    },
    // 激活状态下标签文字颜色
    titleActiveColor: {
      type: String,
      default: '#0a3f81'
    },
    // 未激活状态下标签文字颜色
    titleInactiveColor: {
      type: String,
      default: '#666'
    },
    // 是否省略过长的标题文字
    ellipsis: {
      type: Boolean,
      default: true
    },
    // 是否显示标签对应的内容区域
    showContent: {
      type: Boolean,
      default: false
    },
    // 是否使用大尺寸标签样式
    largeSize: {
      type: Boolean,
      default: true
    },
    // 标签栏高度，单位rpx
    tabHeight: {
      type: [Number, String],
      default: 140
    }
  },
  data() {
    return {
      active: this.value,         // 当前激活的标签索引，初始值来自props
      lineWidth: 40,              // 底部指示线宽度，单位px
      lineHeight: 3,              // 底部指示线高度，单位px
      lineOffset: 0,              // 底部指示线的水平偏移量
      scrollOffset: 0,            // 记录滚动位置的偏移量
      scrollLeft: 0,              // scroll-view的滚动位置
      stickyFixed: false,         // 是否处于吸顶状态
      tabRects: [],               // 存储所有标签的位置信息
      isFirstRender: true,        // 是否为首次渲染，用于控制动画
      isH5: false,                // 是否为H5环境
      isMp: false,                // 是否为小程序环境
      localDuration: this.duration // 本地动画过渡时间，可动态调整
    }
  },
  computed: {
    cssVars() {
      return {
        '--tabs-height': `${this.tabHeight}rpx`,
        '--active-color': this.titleActiveColor,
        '--inactive-color': this.titleInactiveColor
      };
    },
    // 移除了lineStyle和navStyle计算属性，样式已直接写在DOM元素上
  },
  watch: {
    /**
     * 监听外部传入的value值变化
     * 当父组件通过v-model更新value时触发
     * @param {Number} val - 新的激活标签索引
     */
    value(val) {
      // 只有当新值与当前激活值不同时才更新
      if (val !== this.active) {
        // 更新当前激活的标签索引
        this.active = val;
        // 等待DOM更新后执行
        this.$nextTick(() => {
          setTimeout(() => {
            // 更新底部指示线位置
            this.setLine();
            // 滚动到当前激活的标签
            this.scrollIntoView();
          }, 50); // 短暂延迟确保DOM已更新
        });
      }
    },
    /**
     * 监听内部active值变化
     * 当组件内部切换标签时触发
     */
    active() {
      this.$nextTick(() => {
        setTimeout(() => {
          // 更新底部指示线位置
          this.setLine();
          // 滚动到当前激活的标签
          this.scrollIntoView();
          // 触发v-model双向绑定的input事件
          this.$emit('input', this.active);
          // 触发标签切换的change事件
          this.$emit('change', this.active);
        }, 50); // 短暂延迟确保DOM已更新
      });
    },
    /**
     * 监听标签项数组变化
     * 当标签数据更新时重新计算位置信息
     */
    items() {
      this.$nextTick(() => {
        setTimeout(() => {
          // 更新所有标签的位置信息
          this.updateTabRects().then(() => {
            // 更新底部指示线位置
            this.setLine();
            // 滚动到当前激活的标签
            this.scrollIntoView();
          });
        }, 100); // 较长延迟确保DOM完全更新
      });
    },
    /**
     * 监听动画过渡时间变化
     * @param {Number|String} val - 新的过渡时间值
     */
    duration(val) {
      // 更新本地动画过渡时间
      this.localDuration = val;
    }
  },
  /**
   * 组件创建时的生命周期钩子
   * 用于检测当前运行环境（H5或小程序）
   */
  created() {
    // 使用条件编译检测当前运行环境
    // #ifdef H5
    // H5环境标记
    this.isH5 = true;
    // #endif
    
    // #ifdef MP
    // 小程序环境标记
    this.isMp = true;
    // #endif
  },
  /**
   * 组件挂载到DOM后的生命周期钩子
   * 初始化标签栏并设置事件监听
   */
  mounted() {
    this.$nextTick(() => {
      // 延迟初始化，确保DOM已渲染完成
      setTimeout(() => {
        this.isFirstRender = true;
        // 初始化标签栏（计算位置、设置指示线等）
        this.initTabs();
      }, 100);
      
      // 仅在H5环境下添加窗口大小变化的事件监听
      if (this.isH5 && typeof window !== 'undefined') {
        // 添加resize事件监听
        window.addEventListener('resize', this.onWindowResize);
        
        // 通过JavaScript直接隐藏滚动条
        setTimeout(() => {
          const scrollViewEls = document.querySelectorAll('.custom-tabs__wrap--scrollable .uni-scroll-view, .custom-tabs__wrap--scrollable .uni-scroll-view .uni-scroll-view');
          scrollViewEls.forEach(el => {
            if(el) {
              el.style.overflow = 'auto';
              el.style.overflowX = 'auto';
              el.style.overflowY = 'hidden';
              el.style.webkitOverflowScrolling = 'touch';
              el.style.scrollbarWidth = 'none';
              el.style.msOverflowStyle = 'none';
            }
          });
        }, 100);
        
        // 在组件销毁前移除事件监听（Vue 2.x生命周期）
        this.$once('hook:beforeDestroy', () => {
          window.removeEventListener('resize', this.onWindowResize);
        });
        
        // 在组件销毁前移除事件监听（Vue 3.x生命周期）
        this.$once('hook:beforeUnmount', () => {
          window.removeEventListener('resize', this.onWindowResize);
        });
      }
    });
  },
  methods: {
    /**
     * 初始化标签栏
     * 组件的核心初始化方法，负责计算位置、设置指示线和滚动位置
     */
    async initTabs() {
      try {
        // 更新所有标签的位置信息（宽度、高度、位置等）
        await this.updateTabRects();
        
        // 设置底部指示线位置，使其对应当前激活的标签
        await this.setLine();
        
        // 滚动到当前激活的标签，确保其可见
        await this.scrollIntoView();
        
        // 如果启用了吸顶功能，初始化相关事件监听
        if (this.sticky) {
          this.initSticky();
        }
        
        // 添加窗口大小变化监听（仅在H5环境且未添加过）
        if (this.isH5 && typeof window !== 'undefined' && !this._resizeListenerAdded) {
          this._resizeListenerAdded = true;
          window.addEventListener('resize', this.onResize);
        }
        
        // 延迟标记首次渲染完成，确保所有初始化动画已结束
        setTimeout(() => {
          this.isFirstRender = false;
        }, 300); // 300ms后启用过渡动画
      } catch (error) {
        console.error('initTabs error:', error);
      }
    },
    
    /**
     * 获取标签的样式对象
     * 根据标签是否激活返回不同的文字颜色
     * @param {Number} index - 标签索引
     * @returns {Object} 样式对象
     */
    getTabStyle(index) {
      const style = {};
      // 根据标签是否为当前激活项设置不同的文字颜色
      if (index === this.active) {
        style.color = this.titleActiveColor; // 激活状态颜色
      } else {
        style.color = this.titleInactiveColor; // 未激活状态颜色
      }
      return style;
    },
    
    /**
     * 标签项点击事件处理函数
     * @param {Object} item - 被点击的标签项数据
     * @param {Number} index - 被点击的标签项索引
     */
    onItemClick(item, index) {
      // 如果标签被禁用，触发disabled事件并返回
      if (item.disabled) {
        this.$emit('disabled', index);
        return;
      }
      
      // 更新当前激活的标签索引
      this.active = index;
      // 触发点击事件
      this.$emit('click', index);
      // 触发v-model双向绑定的input事件
      this.$emit('input', index);
      
      // 等待DOM更新后执行
      this.$nextTick(() => {
        setTimeout(() => {
          // 更新底部指示线位置
          this.setLine();
          // 滚动视图以确保当前标签可见
          this.scrollIntoView();
          // 将当前标签滚动到中心位置
          this.scrollToCenter();
        }, 50); // 延迟执行以确保DOM已更新
      });
    },
    
    /**
     * 更新所有标签的位置信息
     * 该方法获取每个标签的尺寸和位置，用于后续的滚动和指示线定位
     * @returns {Array} 返回所有标签的位置信息数组
     */
    async updateTabRects() {
      // 如果没有标签项，直接返回
      if (!this.items.length) return;
      
      try {
        // 获取导航容器的位置信息
        const navRect = await this.getRect('#scroll-nav-bar-nav');
        if (!navRect) return;
        
        // 并行获取所有标签的位置信息
        const promises = this.items.map((_, index) => 
          this.getRect(`#scroll-nav-bar-item-${index}`)
        );
        
        const rects = await Promise.all(promises);
        
        // 处理获取到的标签位置信息
        let accumulatedLeft = 0; // 用于计算累积左偏移
        this.tabRects = rects.map((rect, index) => {
          if (!rect) {
            // 如果无法获取到标签位置，使用估算值（容错处理）
            const estimatedWidth = 100; // 估算宽度
            const result = {
              width: estimatedWidth,
              height: 40,
              left: accumulatedLeft,
              estimated: true // 标记为估算值，便于后续识别
            };
            accumulatedLeft += estimatedWidth;
            return result;
          }
          
          // 计算相对于导航容器的位置
          const result = {
            width: rect.width,
            height: rect.height,
            left: rect.left - navRect.left, // 相对于导航容器的左偏移
            absolute: rect.left // 保存绝对位置，用于后续计算
          };
          
          // 更新累积左偏移
          accumulatedLeft = result.left + result.width;
          return result;
        });
        
        // 计算导航栏的总宽度，确保能容纳所有标签
        let totalWidth = 0;
        this.tabRects.forEach(rect => {
          if (rect) totalWidth += rect.width;
        });
        
        // 如果总宽度小于容器宽度，确保导航栏至少占满容器
        if (totalWidth < navRect.width) {
          totalWidth = navRect.width;
        }
        
        // 修正首尾标签的位置，确保良好的滚动体验
        if (this.tabRects.length > 0) {
          // 确保第一个标签从0开始，优化滚动体验
          if (this.tabRects[0].left > 0) {
            const offset = this.tabRects[0].left;
            this.tabRects.forEach(rect => {
              if (rect) rect.left -= offset;
            });
          }
        }
        
        console.log('标签位置信息:', this.tabRects);
        
        return this.tabRects;
      } catch (error) {
        console.error('updateTabRects error:', error);
        return [];
      }
    },
    
    /**
     * 设置底部指示线的位置和宽度
     * 根据当前激活的标签计算指示线的位置，并应用平滑过渡动画
     */
    async setLine() {
      try {
        // 并行获取当前激活标签和导航容器的位置信息
        const [tabRect, navRect] = await Promise.all([
          this.getRect(`#scroll-nav-bar-item-${this.active}`),
          this.getRect('#scroll-nav-bar-nav')
        ]);
        
        // 如果无法获取位置信息，直接返回
        if (!tabRect || !navRect) return;
        
        // 计算指示线的宽度，使用固定宽度确保一致性
        // 使用固定宽度40px，确保所有标签下的指示线宽度一致
        this.lineWidth = 40;
        
        // 计算指示线的水平偏移量，确保在标签下方精确居中对齐
        const offsetLeft = tabRect.left - navRect.left;
        // 计算标签的中心点位置
        const tabCenter = offsetLeft + (tabRect.width / 2);
        // 将指示线放置在标签中心点，减去指示线宽度的一半以确保居中
        this.lineOffset = tabCenter - (this.lineWidth / 2);
        
        console.log('指示线位置计算:', {
          tabWidth: tabRect.width,
          offsetLeft,
          tabCenter,
          lineWidth: this.lineWidth,
          lineOffset: this.lineOffset
        });
        
        // 应用平滑过渡动画，首次渲染时不使用动画（避免初始闪烁）
        this.localDuration = this.isFirstRender ? 0 : 0.3;
        
        // 首次渲染后标记为非首次，后续将启用过渡动画
        if (this.isFirstRender) {
          this.isFirstRender = false;
        }
      } catch (error) {
        console.error('setLine error:', error);
      }
    },
    
    /**
     * 滚动视图以确保当前激活的标签可见
     * 计算滚动位置，使当前标签尽可能居中显示
     */
    async scrollIntoView() {
      // 如果不允许滚动，直接返回
      if (!this.scrollable) return;
      
      try {
        // 并行获取包裹容器和当前激活标签的位置信息
        const [wrapRect, tabRect] = await Promise.all([
          this.getRect('.custom-tabs__wrap'),
          this.getRect(`#scroll-nav-bar-item-${this.active}`)
        ]);

        // 如果无法获取位置信息，记录错误并返回
        if (!wrapRect || !tabRect) {
          console.error('无法获取元素位置信息');
          return;
        }
        
        console.log('容器宽度:', wrapRect.width, '标签宽度:', tabRect.width);
        
        // 计算当前标签的中心位置（相对于视口）
        const tabCenter = tabRect.left + tabRect.width / 2;
        
        // 计算容器的中心位置（相对于视口）
        const wrapCenter = wrapRect.left + wrapRect.width / 2;
        
        // 计算需要滚动的距离，使标签中心与容器中心对齐
        // 当前滚动位置 + 需要调整的偏移量
        let scrollOffset = this.scrollOffset + (tabCenter - wrapCenter);
        
        // 获取所有标签的总宽度（导航栏的宽度）
        const navRect = await this.getRect('#scroll-nav-bar-nav');
        if (!navRect) return;
        
        // 计算最大可滚动距离，防止过度滚动
        const maxScrollOffset = Math.max(0, navRect.width - wrapRect.width);
        
        // 限制滚动范围，确保不会滚动到负值或超过最大值
        scrollOffset = Math.max(0, Math.min(scrollOffset, maxScrollOffset));
        
        console.log('滚动计算:', {
          tabCenter,
          wrapCenter,
          scrollOffset,
          maxScrollOffset,
          navWidth: navRect.width,
          wrapWidth: wrapRect.width
        });
        
        // 应用滚动偏移 - 使用 scrollLeft 属性控制 scroll-view 的滚动位置
        this.scrollLeft = scrollOffset;
        
        // 应用平滑滚动动画，首次渲染时不使用动画
        this.localDuration = this.isFirstRender ? 0 : 0.3;
      } catch (error) {
        console.error('scrollIntoView error:', error);
      }
    },
    
    /**
     * 初始化吸顶功能
     * 根据不同运行环境（小程序/H5）添加相应的滚动监听
     */
    initSticky() {
      // 如果未启用吸顶功能，直接返回
      if (!this.sticky) return;
      
      // 小程序环境下的处理
      if (this.isMp) {
        // 获取当前页面实例
        const page = getCurrentPages()[getCurrentPages().length - 1];
        if (page && page.onPageScroll) {
          // 保存原有的页面滚动事件处理函数
          const originalOnPageScroll = page.onPageScroll;
          // 重写页面滚动事件，在调用原有函数的同时执行组件的滚动处理
          page.onPageScroll = (e) => {
            if (originalOnPageScroll) {
              originalOnPageScroll(e);
            }
            this.onPageScroll(e);
          };
        }
      } 
      // H5环境下的处理
      else if (this.isH5 && typeof window !== 'undefined') {
        // 添加窗口滚动事件监听
        window.addEventListener('scroll', this.onWindowScroll);
        // 组件销毁前移除事件监听（Vue 2.x生命周期）
        this.$once('hook:beforeDestroy', () => {
          window.removeEventListener('scroll', this.onWindowScroll);
        });
        
        // 组件销毁前移除事件监听（Vue 3.x生命周期）
        this.$once('hook:beforeUnmount', () => {
          window.removeEventListener('scroll', this.onWindowScroll);
        });
      }
    },
    
    /**
     * 处理小程序环境下的页面滚动事件
     * 用于实现吸顶效果
     * @param {Object} e - 滚动事件对象
     */
    async onPageScroll(e) {
      try {
        // 获取导航栏元素的位置信息
        const navRect = await this.getRect('#scroll-nav-bar-nav');
        if (!navRect) return;
        
        // 获取元素距离顶部的距离
        const { top } = navRect;
        // 转换offsetTop为数字类型
        const offsetTop = Number(this.offsetTop);
        // 当元素顶部距离小于等于设定的偏移量时，启用吸顶效果
        this.stickyFixed = top <= offsetTop;
      } catch (error) {
        // 错误处理（静默）
      }
    },
    
    /**
     * 处理H5环境下的窗口滚动事件
     * 用于实现吸顶效果
     */
    onWindowScroll() {
      this.getRect('#scroll-nav-bar-nav').then(navRect => {
        if (!navRect) return;
        
        // 获取元素距离顶部的距离
        const { top } = navRect;
        // 转换offsetTop为数字类型
        const offsetTop = Number(this.offsetTop);
        // 当元素顶部距离小于等于设定的偏移量时，启用吸顶效果
        this.stickyFixed = top <= offsetTop;
      }).catch(error => {
        // 错误处理（静默）
      });
    },
    
    /**
     * 窗口大小变化事件处理函数（H5环境）
     * 调用onResize方法处理大小变化
     */
    onWindowResize() {
      this.onResize();
    },
    
    /**
     * 处理大小变化的核心方法
     * 使用防抖技术避免频繁触发重新计算
     */
    onResize() {
      // 防抖处理，避免频繁触发导致性能问题
      if (this._resizeTimer) {
        clearTimeout(this._resizeTimer);
      }
      
      // 延迟执行重新计算，实现防抖
      this._resizeTimer = setTimeout(async () => {
        // 重新计算所有标签的位置信息
        await this.updateTabRects();
        
        // 更新底部指示线位置
        await this.setLine();
        
        // 重新滚动到当前激活的标签
        await this.scrollIntoView();
      }, 200); // 200ms的防抖延迟
    },
    
    /**
     * 将当前激活的标签滚动到容器中心位置
     * 提供比scrollIntoView更精确的居中定位
     */
    scrollToCenter() {
      // 如果不允许滚动，直接返回
      if (!this.scrollable) return;
      
      try {
        // 使用uni-app的方式获取元素位置信息
        Promise.all([
          this.getRect('.custom-tabs__wrap'),
          this.getRect(`#scroll-nav-bar-item-${this.active}`)
        ]).then(([wrapRect, tabRect]) => {
          if (!wrapRect || !tabRect) return;
          
          // 计算滚动位置，使当前标签居中显示
          const wrapWidth = wrapRect.width; // 容器宽度
          const tabWidth = tabRect.width;   // 标签宽度
          // 计算标签相对于容器的偏移量，考虑当前已滚动的距离
          const tabOffsetLeft = tabRect.left - wrapRect.left + this.scrollLeft;
          
          // 计算需要滚动的距离，使标签居中
          const scrollLeft = tabOffsetLeft - (wrapWidth - tabWidth) / 2;
          
          // 设置滚动位置，确保不会出现负值
          this.scrollLeft = Math.max(0, scrollLeft);
          
          console.log('scroll-view滚动:', {
            wrapWidth,
            tabWidth,
            tabOffsetLeft,
            scrollLeft: this.scrollLeft
          });
        });
      } catch (error) {
        console.error('scrollToCenter失败:', error);
      }
    },
    
    /**
     * 处理scroll-view的滚动事件
     * @param {Object} e - 滚动事件对象
     */
    onScroll(e) {
      // 记录当前滚动位置，用于后续计算
      this.scrollOffset = e.detail.scrollLeft;
    },
    
    /**
     * 滚动视图以确保当前激活的标签可见
     * 计算滚动位置，使当前标签尽可能居中显示
     */
    async scrollIntoView() {
      // 如果不允许滚动，直接返回
      if (!this.scrollable) return;
      
      try {
        // 并行获取包裹容器和当前激活标签的位置信息
        const [wrapRect, tabRect] = await Promise.all([
          this.getRect('.custom-tabs__wrap'),
          this.getRect(`#scroll-nav-bar-item-${this.active}`)
        ]);

        // 如果无法获取位置信息，记录错误并返回
        if (!wrapRect || !tabRect) {
          console.error('无法获取元素位置信息');
          return;
        }
        
        console.log('容器宽度:', wrapRect.width, '标签宽度:', tabRect.width);
        
        // 计算当前标签的中心位置（相对于视口）
        const tabCenter = tabRect.left + tabRect.width / 2;
        
        // 计算容器的中心位置（相对于视口）
        const wrapCenter = wrapRect.left + wrapRect.width / 2;
        
        // 计算需要滚动的距离，使标签中心与容器中心对齐
        // 当前滚动位置 + 需要调整的偏移量
        let scrollOffset = this.scrollOffset + (tabCenter - wrapCenter);
        
        // 获取所有标签的总宽度（导航栏的宽度）
        const navRect = await this.getRect('#scroll-nav-bar-nav');
        if (!navRect) return;
        
        // 计算最大可滚动距离，防止过度滚动
        const maxScrollOffset = Math.max(0, navRect.width - wrapRect.width);
        
        // 限制滚动范围，确保不会滚动到负值或超过最大值
        scrollOffset = Math.max(0, Math.min(scrollOffset, maxScrollOffset));
        
        console.log('滚动计算:', {
          tabCenter,
          wrapCenter,
          scrollOffset,
          maxScrollOffset,
          navWidth: navRect.width,
          wrapWidth: wrapRect.width
        });
        
        // 应用滚动偏移 - 使用 scrollLeft 属性控制 scroll-view 的滚动位置
        this.scrollLeft = scrollOffset;
        
        // 应用平滑滚动动画，首次渲染时不使用动画
        this.localDuration = this.isFirstRender ? 0 : 0.3;
      } catch (error) {
        console.error('scrollIntoView error:', error);
      }
    },
    
    /**
     * 获取DOM元素的位置和尺寸信息
     * 该方法封装了uni-app的选择器查询，并增加了重试机制以提高可靠性
     * @param {String} selector - CSS选择器
     * @returns {Promise<Object>} 返回元素的位置和尺寸信息
     */
    getRect(selector) {
      return new Promise((resolve) => {
        try {
          // 创建uni-app查询选择器对象
          const query = uni.createSelectorQuery();
          
          // 确保在正确的组件作用域内查询
          // 不同版本的uni-app和Vue可能有不同的作用域处理方式
          if (this.$scope) {
            query.in(this.$scope);
          } else if (this.$parent && this.$parent.$scope) {
            query.in(this.$parent.$scope);
          } else {
            query.in(this);
          }
          
          // 添加调试日志，便于排查问题
          console.log('查询元素:', selector);
          
          // 执行查询并获取元素位置信息
          query.select(selector)
            .boundingClientRect(rect => {
              if (rect) {
                // 查询成功，返回元素位置信息
                console.log('获取元素位置成功:', selector, rect);
                resolve(rect);
              } else {
                // 首次查询失败，记录警告并准备重试
                console.warn('首次查询未获取到元素位置，准备重试:', selector);
                // 延迟一段时间后重试，确保DOM已完全渲染
                setTimeout(() => {
                  try {
                    // 创建新的查询对象进行重试
                    const retryQuery = uni.createSelectorQuery();
                    
                    // 同样确保在正确的作用域内查询
                    if (this.$scope) {
                      retryQuery.in(this.$scope);
                    } else if (this.$parent && this.$parent.$scope) {
                      retryQuery.in(this.$parent.$scope);
                    } else {
                      retryQuery.in(this);
                    }
                    
                    // 执行重试查询
                    retryQuery.select(selector)
                      .boundingClientRect(retryRect => {
                        if (retryRect) {
                          console.log('重试获取元素位置成功:', selector, retryRect);
                        } else {
                          console.error('重试获取元素位置失败:', selector);
                        }
                        // 返回重试结果，如果仍然失败则返回null
                        resolve(retryRect || null);
                      })
                      .exec();
                  } catch (retryError) {
                    // 重试过程中发生错误
                    console.error('重试查询失败:', selector, retryError);
                    resolve(null);
                  }
                }, 100); // 增加延迟时间，确保DOM已渲染完成
              }
            })
            .exec();
        } catch (error) {
          // 初始查询过程中发生错误
          console.error('初始查询失败:', selector, error);
          resolve(null);
        }
      });
    }
  }
}
</script>

<style lang="scss">
.custom-tabs {
  width: 100%;
  --tabs-height: 140rpx;
  --active-color: #0a3f81;
  --inactive-color: #666;
  
  &--sticky {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 99;
  }
  
  &__wrap {
    position: relative;
    height: var(--tabs-height);
    overflow: hidden;
    background-color: #fff;
    border-bottom: 1px solid #f5f5f5;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
    
    &--scrollable {
      overflow-x: auto; /* 确保可以水平滚动 */
      overflow-y: hidden;
      -webkit-overflow-scrolling: touch;
      white-space: nowrap;
      scroll-behavior: smooth; /* 添加平滑滚动效果 */
      
      /* 增强滚动条隐藏 */
      &::-webkit-scrollbar,
      .uni-scroll-view::-webkit-scrollbar,
      .uni-scroll-view .uni-scroll-view::-webkit-scrollbar {
        display: none;
      }
    }
    
    &--sticky {
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      z-index: 99;
    }
  }
  
  &__nav {
    position: relative;
    display: flex;
    white-space: nowrap;
    height: var(--tabs-height);
    padding: 10rpx 0;
    box-sizing: border-box;
    transition: transform 0.3s ease;
    width: max-content; /* 确保导航栏宽度能容纳所有选项 */
    min-width: 100%; /* 至少占满容器宽度 */
    will-change: transform; /* 优化性能 */
    
    &::after {
      display: none;
    }
  }
  
  &__item {
    position: relative;
    padding: 0 30rpx;
    cursor: pointer;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: #333;
    font-size: 24rpx;
    transition: all 0.3s;
    height: 120rpx;
    background-color: transparent !important;
    -webkit-tap-highlight-color: transparent; /* 点击时透明高亮 */
    user-select: none;
    -webkit-user-select: none; /* 兼容旧版浏览器内核 */
    
    &--active {
      color: var(--active-color);
      font-weight: bold;
      background-color: transparent !important;
      -webkit-tap-highlight-color: transparent; /* 点击时透明高亮 */
      user-select: none;
      -webkit-user-select: none; /* 兼容旧版浏览器内核 */
      .tab-img {
        transform: scale(1.05);
        border: 2rpx solid var(--active-color);
      }
    }
    
    &--disabled {
      color: #c8c9cc;
      cursor: not-allowed;
    }
    
    &-text {
      width: 100%;
      text-align: center;
      line-height: 1.2;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      transition: all 0.3s;
    }
  }
  
  &__line {
    position: absolute;
    bottom: 0;
    left: 0;
    z-index: 1;
    height: 3px;
    width: 40px !important;
    border-radius: 3px;
    background-color: var(--active-color);
    transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
    transform-origin: center;
    will-change: transform;
    /* 确保指示线在视觉上居中 */
    margin: 0 auto;
  }
  
  &__content {
    overflow: hidden;
  }
}

.tab-img {
  width: 80rpx;
  height: 80rpx;
  border-radius: 50%;
  overflow: hidden;
  background-color: #f8f8f8;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s;
  box-sizing: border-box;
  margin-bottom: 8rpx;
  
  image {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
}
</style>